package mge.particles 
{
  import flash.display.Bitmap;
  import flash.display.BlendMode;
  import flash.display.DisplayObjectContainer;
  import flash.display.Sprite;
  import flash.geom.ColorTransform;
  import flash.geom.Matrix;
  import flash.geom.Rectangle;
  import flash.geom.Vector3D;
  
  /**
   * ...
   * @author ivan
   */
  public class Particle 
  {
    
    public function Particle(bmp:Bitmap, parent:DisplayObjectContainer = null) 
    {
      // Note this is blend mode of this sprite with background elements.
      // sprite.blendMode = BlendMode.ADD; // TODO Do this only once or when needed.
      
      // this.bmp = bmp;
      revive(bmp);
      halfWidth = bmp.width * 0.5;
      halfHeight = bmp.height * 0.5;
    }
    
    public function revive(bmp:Bitmap):void
    {
        // this.bmp = bmp;
        this.bmp = new Bitmap(bmp.bitmapData.clone());
        this.bmp.blendMode = BlendMode.ADD;
        currentLife = 0;
        delta = 0;
        radialVelocity.scaleBy(0);
        _velocity.scaleBy(0);
    }
    
    public function clear():void
    {
    }
    
    public function update(elapsed:Number, sprite:Sprite):void
    {
        var rvs:Vector3D;
        
        // Updates radial velocity
        rvs = initialVelocity.clone();
        rvs.scaleBy(radialAcceleration * elapsed);
        radialVelocity = radialVelocity.add(rvs); 
        
        // Obtains gravity
        var gs:Vector3D = gravity.clone();
        gs.scaleBy(elapsed);
        
        // Updates particle velocity vector.
        _velocity = _velocity.add(radialVelocity);
        _velocity = _velocity.add(gs);
        
        // Updates particle position
        var vs:Vector3D = _velocity.clone();
        vs.scaleBy(elapsed);
        position = position.add(vs);
        
        delta = currentLife / lifeTime;
        
        // Updates particle size
        if (scaleStart != scaleEnd)
            scale = scaleStart * (1 - delta) + scaleEnd * delta;
        
        // spin = spinStart * (1 - delta) + spinEnd * delta;
        
        // Updates particle color
        // if (_colorStart != _colorEnd)
        {
          updateColor(delta);
        }
        
        // Updates particle life
        currentLife += elapsed;
        
        // container.rotation = spinStart * (1 - delta) + spinEnd * delta;
        
        var w:int = bmp.width * _scale;
        
        
        matrix.identity();
        matrix.translate(-halfWidth, -halfWidth);
        matrix.rotate(spinStart * (1 - delta) + spinEnd * delta);
        matrix.scale(_scale, _scale);
        matrix.translate(position.x, position.y);
        
        // sprite.blendMode = BlendMode.ADD;
        sprite.graphics.beginBitmapFill(bmp.bitmapData, matrix, true, true);
        sprite.graphics.drawCircle(position.x, position.y, w * 0.5);
        sprite.graphics.endFill();
    }
    
    private function updateColor(delta:Number):void
    {
        /*
        var colorTransform:ColorTransform = sprite.transform.colorTransform;
        var mixA:uint;
        var mixR:uint;
        var mixG:uint;
        var mixB:uint;
        var q:Number = 1 - delta;
        mixA = colorStartA * q + colorEndA * delta;
        mixR = colorStartR * q + colorEndR * delta;
        mixG = colorStartG * q + colorEndG * delta;
        mixB = colorStartB * q + colorEndB * delta;
        colorTransform.color = (mixA << 24 | mixR << 16 | mixG << 8 | mixB);
        sprite.transform.colorTransform = colorTransform;
        sprite.alpha = mixA / 255;*/
        
        var colorTransform:ColorTransform = new ColorTransform;
        var mixA:uint;
        var mixR:uint;
        var mixG:uint;
        var mixB:uint;
        var q:Number = 1 - delta;
        mixA =  colorStartA * q + colorEndA * delta;
        mixR = colorStartR * q + colorEndR * delta;
        mixG = colorStartG * q + colorEndG * delta;
        mixB = colorStartB * q + colorEndB * delta;
        colorTransform.color = (255 << 24 | mixR << 16 | mixG << 8 | mixB);
        colorTransform.alphaMultiplier = mixA / 255;
        
        bmp.bitmapData.colorTransform(new Rectangle(0, 0, bmp.bitmapData.width, bmp.bitmapData.height), colorTransform);
    }
    
    public function set scale(val:Number):void
    {
      _scale = val;
      
      // container.scaleX = container.scaleY = _scale;
      /*
      var m:Matrix = originalMatrix.clone();
      
      sprite.transform.matrix = originalMatrix;      
      
      m.translate( -(sprite.x + bmp.width*0.5), -(sprite.y + bmp.height*0.5));
      m.scale(_scale, _scale);
      m.translate(sprite.x + bmp.width*0.5, sprite.y + bmp.height*0.5);      
      
      sprite.transform.matrix = m;*/
    }
    
    public function get scale():Number { return _scale; }
    
    public var position:Vector3D = new Vector3D();
    public var gravity:Vector3D = new Vector3D();
    
    public function set velocity(val:Vector3D):void
    {
        val = val.clone();
        initialVelocity = val.clone();
        _velocity = val.clone(); 
    }
    private var _velocity:Vector3D = new Vector3D();
    private var initialVelocity:Vector3D = new Vector3D();
    private var radialVelocity:Vector3D = new Vector3D();
    
    public var radialAcceleration:Number = 0;
    
    public var currentLife:Number = 0;
    public var lifeTime:Number = 1;
    
    public var scaleStart:Number = 1;
    public var scaleEnd:Number = 1;
    
    public var spinStart:Number = 0;
    public var spinEnd:Number = 0;
    
    
    public function set colorStart(val:uint):void
    {
        _colorStart = val;
        colorStartA = (val >> 24) & 0xFF;
        colorStartR = (val >> 16) & 0xFF;
        colorStartG = (val >>  8) & 0xFF;
        colorStartB = (val)       & 0xFF;
        updateColor(0);
    }
    private var _colorStart:uint;
    private var colorStartA:uint;
    private var colorStartR:uint;
    private var colorStartG:uint;
    private var colorStartB:uint;
    
    public function set colorEnd(val:uint):void
    {
        _colorEnd = val;
        colorEndA = (val >> 24) & 0xFF;
        colorEndR = (val >> 16) & 0xFF;
        colorEndG = (val >>  8) & 0xFF;
        colorEndB = (val)       & 0xFF;
        updateColor(0);
    }
    private var _colorEnd:uint;
    private var colorEndA:uint;
    private var colorEndR:uint;
    private var colorEndG:uint;
    private var colorEndB:uint;
    
    private var matrix:Matrix = new Matrix();
    
    private var _scale:Number = 1;
    private var bmp:Bitmap;
    private var halfWidth:int;
    private var halfHeight:int;
    private var delta:Number = 0;
    
  }

}